package com.zk.iotgateway.netty.server;

import com.zk.iotgateway.manager.GlobalManager;
import com.zk.iotgateway.util.NettyUtil;
import com.zk.iotgateway.util.SpringUtil;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.UnpooledByteBufAllocator;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.timeout.IdleStateHandler;

import java.util.concurrent.TimeUnit;

/**
 *
 *服务端，让网关监听我们的ip及端口
 * @author:mn.m
 * @create 2019-04-17 下午 02:36
 **/

public class ServerForTerminal {

    private  String  serverPort;
    private EventLoopGroup boss;
    private  EventLoopGroup work;
    private int length;
    private long allIdleTime;
    public ServerForTerminal(String serverPort,int boss,int work,int length,long allIdleTime){
        this.serverPort = serverPort;
        this.boss = new NioEventLoopGroup(boss);
        /*以jVM线程数为默认*/
        this.work = new NioEventLoopGroup(work);
        this.length=length;
        this.allIdleTime=allIdleTime;
    }

   /*
   * 配置化
   * 自定义解码器
   *
   * */
   public ServerBootstrap config(String decoder,String encoder,String handler){
     ServerBootstrap serverBootstrap=new ServerBootstrap();
       serverBootstrap
               .group(boss, work)
               .channel(NioServerSocketChannel.class)
               .option(ChannelOption.SO_KEEPALIVE, true)
               .option(ChannelOption.TCP_NODELAY, true)
               .option(ChannelOption.ALLOCATOR, UnpooledByteBufAllocator.DEFAULT)
               .option(ChannelOption.SO_BACKLOG,length) //临时存放已完成三次握手的请求的队列的最大长度
               .childOption(ChannelOption.ALLOCATOR, UnpooledByteBufAllocator.DEFAULT) //使用对象池，重用缓冲区
               .childHandler(new ChannelInitializer<SocketChannel>() {

                   @Override
                   protected void initChannel(SocketChannel ch) throws Exception {
                       //心跳检测,超时时间5秒，指定时间中没有读写操作会触发IdleStateEvent事件
                       ch.pipeline().addLast(new IdleStateHandler(0, 0,allIdleTime, TimeUnit.SECONDS));
                       //自定义编解码器  需要在自定义的handler的前面即pipeline链的前端,不能放在自定义handler后面，否则不起作用
                       if (decoder!=null){
                           ch.pipeline().addLast(decoder, (ChannelHandler) SpringUtil.getBean(decoder));
                       }else{
                          // ch.pipeline().addLast(new StringDecoder(Charset.forName("ISO-8859-1")));
                       }
                       if (encoder!=null){
                           ch.pipeline().addLast(encoder, (ChannelHandler) SpringUtil.getBean(encoder));
                       }else {
                          // ch.pipeline().addLast(new StringEncoder(Charset.forName("ISO-8859-1")));
                       }
                       if (handler!=null&&handler.length()>0){
                           String[] handlers=handler.split(",");
                           for(String item:handlers){
                               ch.pipeline().addLast((ChannelHandler) SpringUtil.getBean(item));
                           }

                       }
                   }
               });

       return serverBootstrap;
   }


    /**
     * 绑定服务到指定端口
     * @param serverBootstrap
     */
    public  void bindAddress(ServerBootstrap serverBootstrap){
        ChannelFuture channelFuture;
        try {
            GlobalManager.SERVERMANAGER.put(serverPort,this);
            channelFuture = serverBootstrap.bind(Integer.parseInt(serverPort)).sync();
            System.out.println("网关服务端已启动！！");
            channelFuture.channel().closeFuture().sync();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally{
            NettyUtil.closeEventLoop(boss,work);
        }
    }

    /**
     * 关闭服务
     */
    public void close(){
        NettyUtil.closeEventLoop(boss,work);
        GlobalManager.SERVERMANAGER.remove(this.serverPort);
        System.out.println("成功关闭端口");
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }



}
